package demo4;

import java.util.*;

public class Solution {

    //1.剑指 Offer II 018. 有效的回文
    public boolean isPalindrome(String s) {
        String str = s.toLowerCase();
        char[] ch = str.toCharArray();
        int left = 0;
        int right = ch.length - 1;
        while(left < right) {
            while(left < right &&
                    (ch[left]<'a' || ch[left]>'z') && (ch[left]<'0' || ch[left]>'9')) {
                left++;
            }
            while(left < right &&
                    (ch[right]<'a' || ch[right]>'z') && (ch[right]<'0' || ch[right]>'9')) {
                right--;
            }
            if(ch[left] != ch[right]) {
                return false;
            }
            left++;
            right--;
        }
        return true;
    }

    //2.剑指 Offer II 009. 乘积小于 K 的子数组(滑动窗口)
    public int numSubarrayProductLessThanK(int[] nums, int k) {
        if(k <= 1) {
            return 0;
        }
        int left = 0;
        int right = 0;
        int sum = 1;
        int count = 0;
        while(right < nums.length) {
            sum *= nums[right];
            while (sum >= k) {
                sum /= nums[left];
                left++;
            }
            count += right - left + 1;
            right++;
        }
        return count;
    }

    //3.四数相加 II(哈希表)
    public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
        Map<Integer, Integer> map = new HashMap<>();
        //统计a + b出现的次数
        for(int i = 0; i < nums1.length; i++) {
            for(int j = 0; j < nums2.length; j++) {
                int sum = nums1[i] + nums2[j];
                map.put(sum, map.getOrDefault(sum, 0) + 1);
            }
        }
        int count = 0;
        //找出-(c + d)出现的次数 注释:(a + b) - (c + d) = 0;
        for(int i = 0; i < nums3.length; i++) {
            for(int j = 0; j < nums4.length; j++) {
                int sum = -(nums3[i] + nums4[j]);
                if(map.containsKey(sum)) {
                    count += map.get(sum);
                }
            }
        }
        return count;
    }

//    //4.剑指 Offer II 007. 数组中和为 0 的三个数(排序 + 三指针)
//    public List<List<Integer>> threeSum(int[] nums) {
//        Arrays.sort(nums);
//        List<List<Integer>> ret = new ArrayList<>();
//        for(int i = 0; i < nums.length - 2; i++) {
//            List<Integer> list = new ArrayList<>();
//            int left = i + 1;
//            int right = nums.length - 1;
//            while(left < right) {
//                int sum = nums[i] + nums[left] + nums[right];
//                if (sum > 0) {
//                    right--;
//                } else if(sum < 0) {
//                    left++;
//                } else {
//                    list.add(nums[i]);
//                    list.add(nums[left]);
//                    list.add(nums[right]);
//                    if(!ret.contains(list)) {
//                        ret.add(new ArrayList<>(list));
//                    }
//                    list.clear();
//                    left++;
//                    right--;
//                }
//            }
//        }
//        return ret;
//    }

    //剑指 Offer II 007. 数组中和为 0 的三个数(排序+三指针 + 剪枝)
    public List<List<Integer>> threeSum(int[] nums) {
        Arrays.sort(nums);
        List<List<Integer>> ret = new ArrayList<>();
        for(int i = 0; i < nums.length - 2; i++) {
            //剪枝1：已经排过序了，从i开始大于0，后面就不可能凑出和为0
            if(nums[i] > 0) continue;
            //剪枝2：防止元组重复，因为已经排过序了，所以当a相同的时候，可能会出现相同的元组
            if(i > 0 && nums[i] == nums[i - 1]) continue;
            int left = i + 1;
            int right = nums.length - 1;
            while(left < right) {
                List<Integer> list = new ArrayList<>();
                int sum = nums[i] + nums[left] + nums[right];
                if (sum > 0) {
                    right--;
                } else if(sum < 0) {
                    left++;
                } else {
                    list.add(nums[i]);
                    list.add(nums[left]);
                    list.add(nums[right]);
                    ret.add(list);
                    //剪枝3:去重,当下一个left和right对应的值相等，就直接跳过
                    while(left < right && nums[left] == nums[left + 1]) {
                        left++;
                    }
                    while(left < right && nums[right] == nums[right - 1]) {
                        right--;
                    }
                    left++;
                    right--;
                }
            }
        }
        return ret;
    }

    //5.四数之和(排序+双指针+剪枝)
    public List<List<Integer>> fourSum(int[] nums, int target) {
        Arrays.sort(nums);
        List<List<Integer>> ret = new ArrayList<>();
        //先选定两个值a,b
        for(int i = 0; i < nums.length - 3; i++) {
            for(int j = i + 1; j < nums.length - 2; j++) {
                //1.剪枝
                if(nums[j] > 0 && nums[i] + nums[j] > target) continue;
                //2.剪枝
                if(i > 0 && nums[i] == nums[i - 1]) continue;
                if(j > i + 1 && nums[j] == nums[j - 1]) continue;
                int left = j + 1;
                int right = nums.length - 1;
                while(left < right) {
                    List<Integer> list = new ArrayList<>();
                    int sum = nums[i] + nums[j] + nums[left] + nums[right];
                    if(sum > target) {
                        right--;
                    } else if(sum < target) {
                        left++;
                    } else {
                        list.add(nums[i]);
                        list.add(nums[j]);
                        list.add(nums[left]);
                        list.add(nums[right]);
                        ret.add(list);
                        while(left < right && nums[left] == nums[left + 1]) {
                            left++;
                        }
                        while(left < right && nums[right] == nums[right - 1]) {
                            right--;
                        }
                        left++;
                        right--;
                    }
                }
            }
        }
        return ret;
    }

//    //6.剑指 Offer II 011. 0 和 1 个数相同的子数(前缀和)
//    public int findMaxLength(int[] nums) {
//        //求前缀和a,将数组里的0都替换成-1
//        int len = nums.length;
//        int[] add = new int[len + 1];
//        for(int i = 1; i <= len; i++) {
//            add[i] += nums[i - 1] == 0 ? -1 + add[i - 1] : 1 + add[i - 1];
//        }
//        Map<Integer, Integer> map = new HashMap<>();
//        map.put(0, 0);
//        int maxLen = 0;
//        int sum = 0;
//        for(int i = 1; i <= len; i++) {
//            if(map.containsKey(add[i])) {
//                maxLen = Math.max(maxLen, i - map.get(add[i]));
//            } else {
//                map.put(add[i], i);
//            }
//        }
//        return maxLen;
//    }

    //7.剑指 Offer II 019. 最多删除一个字符得到回文(转换)
    public boolean validPalindrome(String s) {
        int left = 0;
        int right = s.length() - 1;
        while(left < right) {
            if(s.charAt(left) != s.charAt(right)) {
                return isPal(s, left + 1, right) || isPal(s, left, right - 1);
            }
            left++;
            right--;
        }
        return true;
    }

    private boolean isPal(String s, int left, int right) {
        while(left < right) {
            if(s.charAt(left) != s.charAt(right)) {
                return false;
            }
            left++;
            right--;
        }
        return true;
    }

    //8.连续数组(前缀和)
    public int findMaxLength(int[] nums) {
        int len = nums.length ;
        int[] add = new int[len + 1];
        for(int i = 1; i <= len; i++) {
            add[i] = add[i - 1] + (nums[i - 1] == 0 ? -1 : 1);
        }
        Map<Integer, Integer> map = new HashMap<>();
        map.put(0, 0);
        int maxLen = 0;
        for(int i = 1; i <= len; i++) {
            if(!map.containsKey(add[i])) {
                map.put(add[i], i);
            }
            maxLen = Math.max(maxLen, i - map.get(add[i]));
        }
        return maxLen;
    }

    //9.行星碰撞(模拟)
    public int[] asteroidCollision(int[] asteroids) {
        int ans = Integer.MAX_VALUE;
        for(int i = 0; i < asteroids.length; i++) {
            int target = i;
            int cur = i - 1;
            while(cur >= 0 && asteroids[target] < 0 && asteroids[cur] >= 0) {
                if(asteroids[cur] == ans) {
                    cur--;
                    continue;
                }
                if(asteroids[cur] > -asteroids[target]) {
                    asteroids[target] = ans;
                    break;
                } else if(asteroids[cur] == -asteroids[target]) {
                    asteroids[cur] = ans;
                    asteroids[target] = ans;
                    break;
                }
                asteroids[cur] = ans;
                cur--;
            }
        }
        int len = 0;
        for(int num : asteroids) {
            if(num != ans) {
                len++;
            }
        }
        int[] arr = new int[len];
        int index = 0;
        for(int num : asteroids) {
            if(num != ans) {
                arr[index++] = num;
            }
        }
        return arr;
    }

//    //10.小行星碰撞(双端队列)
//    public int[] asteroidCollision(int[] asteroids) {
//        Deque<Integer> stack = new ArrayDeque<>();
//        for(int i = 0; i < asteroids.length; i++) {
//            if(stack.isEmpty()) {
//                stack.offerLast(asteroids[i]);
//                continue;
//            }
//            if(asteroids[i] >= 0) {
//                stack.offerLast(asteroids[i]);
//            } else {
//                while(!stack.isEmpty() && stack.peekLast() > 0 && stack.peekLast() < -asteroids[i]) {
//                    stack.pollLast();
//                }
//                if(stack.isEmpty() || stack.peekLast() < 0) {
//                    stack.offerLast(asteroids[i]);
//                    continue;
//                }
//                if(stack.peekLast() == -asteroids[i]) {
//                    stack.pollLast();
//                }
//            }
//        }
//        int[] arr = new int[stack.size()];
//        int index = 0;
//        while(!stack.isEmpty()) {
//            arr[index++] = stack.pollFirst();
//        }
//        return arr;
//    }


}

class Main {
    public static void main(String[] args) {
        int[] arr = {-2, 1, -1, -2};
        Solution solution = new Solution();
        solution.asteroidCollision(arr);
    }
}
